package ge.telasi.tasks.ui.comp;

import ge.telasi.tasks.ui.Platform;
import ge.telasi.tasks.ui.PrefUtils;
import ge.telasi.tasks.ui.UIUtils;
import ge.telasi.tasks.ui.log.Loggable;
import ge.telasi.tasks.ui.log.Logger;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import static ge.telasi.tasks.ui.log.LoggerUtils.clearLogger;
import static ge.telasi.tasks.ui.log.LoggerUtils.manageException;

/**
 * @author dimitri
 */
public abstract class SimpleTable<T> extends JTable implements Loggable {
    private Logger logger;

    public SimpleTable() {
        setModel(createEmptyModel());
        // set column widthes
        TableColumnModel colModel = getColumnModel();
        Object prefObject = PrefUtils.getObject(getPreferenceName());
        int[] widthes = getDefaultColumnWidthes();
        if (prefObject != null) {
            widthes = (int[]) prefObject;
        }
        try {
            for (int i = 0; i < colModel.getColumnCount(); i++) {
                colModel.getColumn(i).setPreferredWidth(widthes[i]);
            }
        } catch (Exception ex) {}
        colModel.addColumnModelListener(new TableColumnModelListener() {
            public void columnAdded(TableColumnModelEvent e) {}

            public void columnRemoved(TableColumnModelEvent e) {}

            public void columnMoved(TableColumnModelEvent e) {}

            public void columnMarginChanged(ChangeEvent e) {
                saveWidthes();
            }

            public void columnSelectionChanged(ListSelectionEvent e) {}
        });
    }

    private void saveWidthes() {
        TableColumnModel colModel = getColumnModel();
        int[] widthes = new int[colModel.getColumnCount()];
        for (int i = 0; i < colModel.getColumnCount(); i++) {
            TableColumn column = colModel.getColumn(i);
            widthes[column.getModelIndex()] = column.getWidth();
        }
        PrefUtils.putObject(getPreferenceName(), widthes);
    }

    public boolean shouldBeConnected() {
        return true;
    }

    @Override
    public Logger getLogger() {
        return logger;
    }

    @Override
    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    public JComponent[] allFields() {
        return new JComponent[] {};
    }

    public void display(List<T> data) {
        TableModel<T> model = (TableModel<T>) getModel();
        model.setData(data);
    }

    public boolean refresh() {
        if (!shouldBeConnected() || Platform.getDefault().validateConnection()) {
            clearLogger(getLogger(), null);
            try {
                UIUtils.showWaitCursor(this);
                Platform pl = Platform.getDefault();
                List<T> data = getDataFromServer(pl);
                display(data);
                return true;
            } catch (Exception ex) {
                manageException(this, getLogger(), ex);
                return false;
            } finally {
                UIUtils.showCommonCursor(this);
            }
        }
        return false;
    }

    public T getSelection() {
        int index = getSelectedRow();
        if (index != -1) {
            TableModel<T> model = (TableModel<T>) getModel();
            return model.getObjectAt(index);
        }
        return null;
    }

    public List<T> getSelections() {
        int[] indecies = getSelectedRows();
        if (indecies != null && indecies.length > 0) {
            TableModel<T> model = (TableModel<T>) getModel();
            return model.getObjectsAt(indecies);
        }
        return null;
    }

    public void setSelection(T object) {
        TableModel<T> model = (TableModel<T>) getModel();
        int index = model.indexOf(object);
        TableUtils.setSelectionAt(this, index);
    }

    public void setSelections(List<T> objects) {
        TableModel<T> model = (TableModel<T>) getModel();
        int indecies[] = new int[objects.size()];
        int i = 0;
        for (T object : objects) {
            int index = model.indexOf(object);
            indecies[i] = index;
            i++;
        }
        TableUtils.setSelectionAt(this, indecies);
    }

    public List<T> getFullData() {
        TableModel<T> model = (TableModel<T>) getModel();
        return model.getData();
    }

    public void add(T object, boolean inTheEnd) {
        TableModel<T> model = (TableModel<T>) getModel();
        if (inTheEnd) { // place in the end
            if (model.addItem(object)) {
                TableUtils.setSelectionAtEnd(this);
            }
        } else { // place as first record
            if (model.addItemAtHead(object)) {
                TableUtils.setSelectionAt(this, 0);
            }
        }
    }

    public void add(T object) {
        add(object, true);
    }

    public void replace(T object) {
        TableModel<T> model = (TableModel<T>) getModel();
        int index = model.indexOf(object);
        if (model.replaceItemAt(object, index)) {
            TableUtils.setSelectionAt(this, index);
        }
    }

    public void remove(T object) {
        TableModel<T> model = (TableModel<T>) getModel();
        model.removeItem(object);
    }

    public void clearData() {
        TableModel<T> model = (TableModel<T>) getModel();
        model.setData(new ArrayList<T>());
    }

    protected abstract TableModel<T> createEmptyModel();
    protected abstract List<T> getDataFromServer(Platform pl) throws Exception;
    protected abstract String getPreferenceName();
    protected abstract int[] getDefaultColumnWidthes();

}
